package com.hsyg.netty.server;

import com.hsyg.netty.server.handler.ServerHandler2;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * 服务端开发
 */
public class Server2 {
  public static void main(String[] args) {
    int port = 8888;

    if (null != args && args.length > 0) {
      try {
        port = Integer.valueOf(args[0]);

      } catch (Exception e) {
        e.printStackTrace();
      }
    }
    new Server2().bind(port);
  }

  private void bind(int port) {
    //配置服务端的nio线程组；
    //一个用于服务端接受客户端的连接；一个用于记性SocketChannel的网络对鞋
    EventLoopGroup bossGroup = new NioEventLoopGroup();
    EventLoopGroup workGroup = new NioEventLoopGroup();

    try {
      //服务端辅助启动类，用以降低服务端的开发复杂度
      //ServerBootstrap netty用于启动nio服务端的辅助启动类，目的是降低服务端的开发复杂度
      ServerBootstrap bootstrap = new ServerBootstrap();
      bootstrap
        .group(bossGroup, workGroup)
        //实例化ServerSocketChannel
        .channel(NioServerSocketChannel.class)
        //设置ServerSocketChannel的TCP参数
        .option(ChannelOption.SO_BACKLOG, 1024)
        //绑定i/0时间的处理类
        .childHandler(new ChildChannelHandler());

      //绑定端口，同步等待成功 ChannelFuture：代表异步I/O的结果
      //用于异步操作的通知回调
      ChannelFuture future = bootstrap.bind(port).sync();

      //等待服务端监听端口关闭
      //等待服务端链路关闭后main函数才能推出
      future.channel().closeFuture().sync();
    } catch (Exception e) {
      System.out.println("netty Server2 服务端启动异常");
      e.printStackTrace();

    } finally {
      //优雅退出， 释放线程池资源
      workGroup.shutdownGracefully();
      bossGroup.shutdownGracefully();
    }

  }

  /**
   * 主要用于处理网路i/o事件
   */
  private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
      //handler
      ch.pipeline().addLast(new LineBasedFrameDecoder(1024));//判断ByteBuf中的可读字节，判断是否有'\n','\r\n',就依次位置作为结束位置
      ch.pipeline().addLast(new StringDecoder());//将接受到的对象转换成字符串
      ch.pipeline().addLast(new ServerHandler2());
    }

  }


}
